package nyist.media.config.shiro;

import nyist.media.entity.admin.Admin;
import nyist.media.entity.admin.Log;
import nyist.media.repository.AdminRepository;
import nyist.media.repository.LogRepository;
import nyist.media.service.AdminService;
import nyist.media.utils.NetworkUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

import static nyist.media.constant.SystemConstant.MAX_LOGIN_FAIL_COUNT;

/**
 * 登录验证
 */
public class AdminRealm extends AuthorizingRealm {

    @Autowired
    private AdminRepository adminRepository;
    @Autowired
    private AdminService adminService;
    @Autowired
    private LogRepository logRepository;

    /**
     * 获取认证信息
     *
     * @param token 令牌
     * @return 认证信息
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        UsernamePasswordToken authenticationToken = (UsernamePasswordToken) token;
        String username = authenticationToken.getUsername();

        if (StringUtils.isNotEmpty(username) && ArrayUtils.isNotEmpty(authenticationToken.getPassword())) {
            String password = new String(authenticationToken.getPassword());
            Admin admin = adminRepository.findByUsername(username).orElse(null);
            if (admin == null) {
                throw new UnknownAccountException("账号不存在");
            }
            if (!admin.isEnabled()) {
                throw new DisabledAccountException("账号被禁用");
            }
            // 有锁定的，到期：解锁，未到期：提示
            if (admin.getLockIn() != null) {
                if (admin.getLockIn().after(new Timestamp(System.currentTimeMillis()))) {
                    throw new LockedAccountException("您已被锁定至：" + admin.getLockIn().toLocalDateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));
                }
                admin.setLockIn(null);
                admin = adminRepository.save(admin);
            }
            if (StringUtils.isEmpty(password) || !DigestUtils.md5Hex(password).equalsIgnoreCase(admin.getPassword())) {
                admin.setFailCount(admin.getFailCount() + 1);
                if (admin.getFailCount() >= MAX_LOGIN_FAIL_COUNT) {
                    int lockMinute = ((admin.getFailCount() - MAX_LOGIN_FAIL_COUNT) + 1) * 3;
                    admin.setLockIn(new Timestamp(DateUtils.addMinutes(new Date(), lockMinute).getTime()));
                }
                adminRepository.save(admin);
                throw new IncorrectCredentialsException("账号或密码错误");
            } else if (admin.getFailCount() != 0) {
                admin.setFailCount(0);
                admin = adminRepository.save(admin);
            }
            Log log = new Log();
            Date now = new Date();
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();
            log.setIp(NetworkUtil.getIpAddress(request));
            log.setOperator(admin.getUsername());
            log.setOperation("登录");
            log.setCreateDate(now);
            log.setModifyDate(now);
            logRepository.save(log);

            return new SimpleAuthenticationInfo(new Principal(admin.getId(), admin.getUsername(), admin.getName()), password, getName());
        }
        throw new UnknownAccountException("请输入用户名、密码");
    }

    /**
     * 获取授权信息
     *
     * @param principals principals
     * @return 授权信息
     */
    @SuppressWarnings("unchecked")
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Principal principal = (Principal) principals.fromRealm(getName()).iterator().next();
        if (principal != null) {
            Session session = SecurityUtils.getSubject().getSession();
            List<String> authorities = (List<String>) session.getAttribute(Principal.PRINCIPAL_ATTRIBUTE_NAME);
            if (authorities == null) {
                authorities = adminService.findAuthorities(principal.getId());
                session.setAttribute(Principal.PRINCIPAL_ATTRIBUTE_NAME, authorities);
            }
            if (!authorities.isEmpty()) {
                SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
                authorizationInfo.addStringPermissions(authorities);
                return authorizationInfo;
            }
        }
        return null;
    }
}